package rad.framework.mda.jpagen.actions;

import rad.framework.mda.generator.Console;
import rad.framework.mda.generator.util.TypeHelper;
import rad.framework.mda.util.ModelUtil;

import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;

/**
 * @author boudyacho
 * 
 */
public class AddSearchIndexActionExtension extends BaseUtiltiyActionExtension {

	protected static final String INDEXED = "org.hibernate.search.annotations.Indexed";

	protected static final String DOC_ID = "org.hibernate.search.annotations.DocumentId";

	protected static final String ID = "javax.persistence.Id";

	protected static final String FIELD = "org.hibernate.search.annotations.Field";

	protected static final String STORE = "org.hibernate.search.annotations.Store";

	protected static final String INDEX = "org.hibernate.search.annotations.Index";

	public void fillContextMenu(IMenuManager aMenu) {
		getSubMenu(aMenu).add(new AddUniqueNaturalAction());
	}

	protected void execute(Class clazz) {
		if (ModelUtil.isStereotypeApplied(clazz, ENTITY)) {
			addIndexed(clazz);

			EList<NamedElement> list = clazz.getMembers();
			for (NamedElement namedElement : list) {
				if (namedElement instanceof Property) {
					execute((Property) namedElement);
				}
			}
		}
	}

	protected void execute(Property property) {
		if (ModelUtil.isStereotypeApplied(property, ID)) {
			addDocumentId(property);
		} else if ("name,code,title,subject".contains(property.getName())) {
			addTitleField(property);
		} else if ("description,text".contains(property.getName())) {
			addDescriptionField(property);
		} else if (TypeHelper.isStringType(property.getType())
				|| TypeHelper.isText(property)) {
			addField(property);
		}
		// TODO embedded, enum, m2o
		// TODO ??? o2m, m2m, o2o
	}

	protected void addIndexed(NamedElement element) {
		if (!ModelUtil.isStereotypeApplied(element, INDEXED)) {
			Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
					element, INDEXED);
			if (stereotype != null) {
				element.applyStereotype(stereotype);
				element.setValue(stereotype, "index", "rad-framework");
				Console.getStream().println(
						"Added Indexed - " + element.getQualifiedName());
			}
		}
	}

	protected void addDocumentId(NamedElement element) {
		if (!ModelUtil.isStereotypeApplied(element, DOC_ID)) {
			Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
					element, DOC_ID);
			if (stereotype != null) {
				element.applyStereotype(stereotype);
				Console.getStream().println(
						"Added Index Document Id - "
								+ element.getQualifiedName());
			}
		}
	}

	protected void addTitleField(NamedElement element) {
		if (!ModelUtil.isStereotypeApplied(element, FIELD)) {
			Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
					element, FIELD);
			if (stereotype != null) {
				element.applyStereotype(stereotype);
				element.setValue(stereotype, "name", "title");
				setStore(element, stereotype);
				setIndex(element, stereotype);
				Console.getStream().println(
						"Added Index Title Field - "
								+ element.getQualifiedName());
			}
		}
	}

	protected void addDescriptionField(NamedElement element) {
		if (!ModelUtil.isStereotypeApplied(element, FIELD)) {
			Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
					element, FIELD);
			if (stereotype != null) {
				element.applyStereotype(stereotype);
				element.setValue(stereotype, "name", "description");
				setStore(element, stereotype);
				setIndex(element, stereotype);
				Console.getStream().println(
						"Added Index Description Field - "
								+ element.getQualifiedName());
			}
		}
	}

	protected void addField(NamedElement element) {
		if (!ModelUtil.isStereotypeApplied(element, FIELD)) {
			Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
					element, FIELD);
			if (stereotype != null) {
				element.applyStereotype(stereotype);
				setIndex(element, stereotype);
				Console.getStream().println(
						"Added Index Field - " + element.getQualifiedName());
			}
		}
	}

	protected void setStore(Element element, Stereotype stereotype) {
		Element e = ModelUtil.getProfileElement(element, STORE);
		if (e != null) {
			if (e instanceof Enumeration) {
				element.setValue(stereotype, "store", ((Enumeration) e)
						.getOwnedLiteral("YES"));
			}
		}
	}

	protected void setIndex(Element element, Stereotype stereotype) {
		Element e = ModelUtil.getProfileElement(element, INDEX);
		if (e != null) {
			if (e instanceof Enumeration) {
				// NOTE - only strings should be tokenized
				element.setValue(stereotype, "index", ((Enumeration) e)
						.getOwnedLiteral("TOKENIZED"));
			}
		}
	}

	private class AddUniqueNaturalAction extends BaseUtilityAction {
		private static final String LABEL = "Add Search Index Stereotypes";

		public AddUniqueNaturalAction() {
			super(LABEL);
		}
	}
}
